package fun.yyds.service.es;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import fun.yyds.common.page.PageData;
import fun.yyds.entity.es.EsLogDocument;
import fun.yyds.entity.es.vo.EsLogVO;
import fun.yyds.utils.LogUtil;
import lombok.RequiredArgsConstructor;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
public class EsLogService {

    @Resource
    private final ElasticsearchRestTemplate esTemplate;

    public PageData<EsLogVO> searchByMessage(String logType, String keyword, int currentPage, int pageSize) {
        // PageRequest分页从0开始 需要-1
        PageRequest pageable = PageRequest.of(currentPage - 1, pageSize);
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        if (StringUtils.isNotBlank(keyword)) {
            boolQuery.must(QueryBuilders.termQuery("content", keyword));
        }
        if (StringUtils.isNotBlank(logType)) {
            boolQuery.must(QueryBuilders.termQuery("logType.keyword", logType));
        }
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder()
                .withQuery(boolQuery)
                .withSorts(SortBuilders.fieldSort("@timestamp").order(SortOrder.DESC))
                .withPageable(pageable);
        NativeSearchQuery query = queryBuilder.build();

        SearchHits<EsLogDocument> searchHits = esTemplate.search(query, EsLogDocument.class);
        long totalHits = searchHits.getTotalHits();

        List<EsLogVO> vos = searchHits.stream().map(SearchHit::getContent).map(this::convertToVo).collect(Collectors.toList());

        LogUtil.infoLog("日志查询完成");
        return new PageData<>(
                vos,
                (int) totalHits,
                pageSize,
                currentPage);
    }

    /**
     * 使用 Search After 实现深度分页查询
     */
    public PageData<EsLogVO> searchByMessage2(String logType, String keyword, int currentPage, int pageSize, Object[] searchAfter) {
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();

        if (StringUtils.isNotBlank(keyword)) {
            boolQuery.must(QueryBuilders.matchQuery("content", keyword));
        }

        if (StringUtils.isNotBlank(logType)) {
            boolQuery.must(QueryBuilders.termQuery("logType.keyword", logType));
        }

        // 构建排序条件
        FieldSortBuilder timestampSort = SortBuilders.fieldSort("@timestamp")
                .order(SortOrder.DESC);
        FieldSortBuilder idSort = SortBuilders.fieldSort("_id")
                .order(SortOrder.ASC); // 添加_id作为第二排序条件确保唯一性

        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder()
                .withQuery(boolQuery)
                .withSorts(timestampSort, idSort)
                .withPageable(PageRequest.of(0, pageSize)); // 这里page设置为0，因为我们使用searchAfter

        // 如果是后续分页，添加searchAfter参数
        if (searchAfter != null && searchAfter.length > 0) {
            queryBuilder.withSearchAfter(Arrays.asList(searchAfter));
        }

        NativeSearchQuery query = queryBuilder.build();

        SearchHits<EsLogDocument> searchHits = esTemplate.search(query, EsLogDocument.class);
        long totalHits = searchHits.getTotalHits();

        List<EsLogVO> vos = searchHits.stream()
                .map(SearchHit::getContent)
                .map(this::convertToVo)
                .collect(Collectors.toList());

        // 获取最后一个结果的排序值，用于下一次searchAfter
        Object[] lastSortValues = null;

        // 使用迭代器找到最后一个元素
        Iterator<SearchHit<EsLogDocument>> iterator = searchHits.iterator();
        SearchHit<EsLogDocument> lastHit = null;

        while (iterator.hasNext()) {
            lastHit = iterator.next();
        }

        if (lastHit != null) {
            lastSortValues = lastHit.getSortValues().toArray();
        }

        LogUtil.infoLog("日志查询完成，使用Search After分页");

        // 返回包含searchAfter信息的分页结果
        return new PageData<>(
                vos,
                (int) totalHits,
                pageSize,
                currentPage,
                lastSortValues);
    }


    private EsLogVO convertToVo(EsLogDocument esLogDocument) {
        return BeanUtil.copyProperties(esLogDocument, EsLogVO.class);
    }

    public String backupLog() {
        return null;
    }

}